package Tracer;

/*
 * @(#)Colour.java     1.0         2009/09/12
 * Copyright(c)  2009 Autumn Large Scale Programming Group Feel
 * Uppsala University,  Sweden
 * All right reserved.
 * file description
 */

/**
 * ClassName : RTVector It's an abstract data type to describe vectors with all
 * of its basic algebra which will be further used in the computing steps of ray
 * tracer. Many concept in the three dimensional space is represented by
 * vectors, such as point and direction, so an abstract vector class is a base
 * for the whole ray tracer class. Since we use the left-hand coordination
 * system, three values are used to represent a vector, in the RTVector class we
 * use three values of double type as its internal attribute, used to store
 * X,Y,Z of a vector separately. Double type can ensure a precision for each
 * value.
 * 
 * @version 1.0 Sep. 10th 2009
 * @author PENG ZHANG
 */
public class RTVector {
	/**
	 *the X coordination of vector
	 */
	private double vx;
	/**
	 *the Y coordination of vector
	 */
	private double vy;
	/**
	 *the Z coordination of vector
	 */
	private double vz;

	/**
	 * Class Constructor This is a default constructor to initialize the numbers
	 * with zero, so if a class user create a RTVector with no arguments, a
	 * default contructor will be called and a (0,0,0) vector will be obtained.
	 */
	public RTVector() {
		vx = 0;
		vy = 0;
		vz = 0;
	}

	/**
	 * Class Constructor This is a copy constructor with an argument of its own
	 * type. We can call this constructor by passing an already existing
	 * RTVector instance.
	 * 
	 * @param vector
	 *            an RTVector object which is used for initialize
	 */
	public RTVector(final RTVector vector) {
		vx = vector.vx;
		vy = vector.vy;
		vz = vector.vz;
	}

	/**
	 * Class Constructor This is a constructor used to create a new RTVector
	 * with three arguments of double type.
	 * 
	 * @param X
	 *            the X value which is set to the X coordinate of the vector
	 * @param Y
	 *            the Y value which is set to the Y coordinate of the vector
	 * @param Z
	 *            the Z value which is set to the Z coordinate of the vector
	 */
	public RTVector(final double x, final double y, final double z) {
		vx = x;
		vy = y;
		vz = z;
	}

	/**
	 * Set the X,Y,Z value for a vector
	 * 
	 * @param valueX
	 *            the X value which is set to the X coordinate of the vector
	 * @param valueY
	 *            the Y value which is set to the Y coordinate of the vector
	 * @param valueZ
	 *            the Z value which is set to the Z coordinate of the vector
	 */
	public final void setVector(final double valueX, final double valueY,
			final double valueZ) {
		vx = valueX;
		vy = valueY;
		vz = valueZ;
	}

	/**
	 * This is a method to operate a dot product of two Vectors and we design it
	 * as a static method so that the class user can call it as a class method
	 * and pass two RTVectors as arguments, the return is a double type value
	 * after operating dot product operation.
	 * 
	 * @param u
	 *            first input vector
	 * @param v
	 *            second input vector
	 * @return return double returns a real-valued scalar quantity
	 */
	public static final double dotProductVectors(final RTVector u,
			final RTVector v) {
		double result = u.vx * v.vx + u.vy * v.vy + u.vz * v.vz;
		return result;
	}

	/**
	 * This method is a binary operation on two vectors in a three-dimensional
	 * space that results in another vector which is perpendicular to the plane
	 * containing the two input vectors.
	 * 
	 * @param u
	 *            first input vector
	 * @param v
	 *            second input vector
	 * @return return RTVector returns a vector
	 */
	public static final RTVector crossProductVectors(final RTVector u,
			final RTVector v) {
		RTVector result = new RTVector();

		result.setVector(u.vy * v.vz - u.vz * v.vy, u.vz * v.vx - u.vx * v.vz,
				u.vx * v.vy - u.vy * v.vx);
		return result;
	}

	/**
	 * This method is a operation on two vectors which returns the sum
	 * 
	 * @param u
	 *            first input vector
	 * @param v
	 *            second input vector
	 * @return return RTVector returns a vector which is sum of u and v
	 */
	public static final RTVector sumVectors(final RTVector u, final RTVector v) {
		RTVector result = new RTVector();
		result.setVector(u.vx + v.vx, u.vy + v.vy, u.vz + v.vz);
		return result;
	}

	/**
	 * This method is to calculate a multiplication of RTVector and double type
	 * number, it's realized by multiply every value of RTVector by the double
	 * type argument, so the return result of calling this method is also a
	 * RTVector.
	 * 
	 * @param u
	 *            input vector
	 * @param s
	 *            mutable value which is a double
	 * @return return RTVector returns a vector which is multiple with value s
	 */
	public static final RTVector multipleVectors(final RTVector u,
			final double s) {
		RTVector result = new RTVector();
		result.setVector(u.vx * s, u.vy * s, u.vz * s);
		return result;
	}

	/**
	 * This method is used to calculate the length of a vector, we simply
	 * initialize the length to return into -1 which is illegal as a length,
	 * when the class user want to use this method, he can pass a RTVector as an
	 * argument and then get a double value representing the length of this *
	 * RTVector.
	 * 
	 * @param u
	 *            the input vector
	 * @return return is the length of vector
	 */
	public static final double calVectorLength(final RTVector u) {
		double length = -1;
		double dotvValue = dotProductVectors(u, u);
		length = (double) java.lang.Math.sqrt(dotvValue);
		return length;
	}

	/**
	 * This method is a operation which returns a unit vector
	 * 
	 * @param u
	 *            the input vector
	 * @return return RTVector a unit vector in a normed vector space is a
	 *         vector (often a spatial vector) whose length is 1 (the unit
	 *         length).
	 */
	public static final RTVector normaliseVectors(final RTVector u) {
		RTVector result = new RTVector();
		double vectorsLen = calVectorLength(u);
		if (vectorsLen > 0) {
			result = multipleVectors(u, 1 / vectorsLen);
		}
		return result;
	}

	/**
	 * This method is an operation which returns the reverse of a vector
	 * 
	 * @param u
	 *            the input vector
	 * @return return RTVector a reverse vector
	 */
	public static final RTVector reverseVector(final RTVector u) {
		RTVector result = new RTVector();
		result.setVector(-u.vx, -u.vy, -u.vz);
		return result;
	}

	/**
	 * This method compare two vectors, true if two vectors have equal values
	 * otherwise false
	 * 
	 * @param v
	 *            the input vector
	 * @return return a boolean value
	 */
	public final boolean isEqual(final RTVector v) {
		if (v.vx == vx && v.vy == vy && v.vz == vz) {
			return true;
		} else {
			return false;
		}
	}

}
